﻿#include "pch.h"
#include "framework.h"
#include "MiniFlasher.h"
#include "MiniFlasherDlg.h"
#include "afxdialogex.h"
#include "jlink.h"
#include <stdarg.h>
#include <stdio.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CMiniFlasherDlg 对话框
CMiniFlasherDlg::CMiniFlasherDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_MINIFLASHER_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CMiniFlasherDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_COMBO1, m_iface);
	DDX_Control(pDX, IDC_COMBO2, m_speed);
	DDX_Control(pDX, IDC_EDIT3, m_editAddr);
	DDX_Control(pDX, IDC_EDIT2, m_editPath);
	DDX_Control(pDX, IDC_EDIT1, m_editName);
	DDX_Control(pDX, IDC_LIST2, m_listLog);
	DDX_Control(pDX, IDC_BUTTON4, m_btnProg);
}

void CMiniFlasherDlg::AppendMessage(const char *fmt, ...)
{
	va_list va;
	SYSTEMTIME st;
	char buf[1024];
	GetLocalTime(&st);
	int len = snprintf(buf, 1024, "[%02d:%02d:%02d]", st.wHour, st.wMinute, st.wSecond);
	va_start(va, fmt);
	vsnprintf(&buf[len], sizeof(buf), fmt, va);
	va_end(va);
	m_listLog.AddString(buf);
}

void CMiniFlasherDlg::ClearMessage(void)
{
	m_listLog.ResetContent();
}

BOOL CMiniFlasherDlg::JLinkSetup(void)
{
	int   ret;
	DWORD val;
	char  cmd[256];
	ret = JLINK_Open();
	if (ret != 0)
	{
		AppendMessage("Can not connect to JLink!\n");
		return FALSE;
	}
	val = JLINK_GetHardwareVersion();
	AppendMessage("JLink HW: %u.%u\n", val/10000, val%10000);
	AppendMessage("JLink SN: %u\n", JLINK_GetSN());

	int tif = m_iface.GetCurSel();
	theApp.WriteProfileInt("target", "tif", tif);
	JLINK_TIF_Select(tif);

	int speed = m_speed.GetCurSel();
	theApp.WriteProfileInt("target", "speed", speed);
	speed = GetDlgItemInt(IDC_COMBO2);
	JLINK_SetSpeed(speed);

	char name[128];
	m_editName.GetWindowTextA(name, 128);
	snprintf(cmd, sizeof(cmd) - 1, "device=%s", name);
	JLINK_ExecCommand(cmd, 0, 0);

	AppendMessage("Connect device...\n");
	ret = JLINK_Connect();
	if (ret < 0)
	{
		JLINK_Close();
		AppendMessage("Can not connect to device!\n");
		return FALSE;
	}
	JLINK_Halt();
	val = JLINK_GetSpeed();
	AppendMessage("Speed:    %dKHz\n", val);
	val = JLINK_GetId();
	AppendMessage("CoreID:   0x%08X\n", val);
	AppendMessage("Connect OK.\n");
	return TRUE;
}

BEGIN_MESSAGE_MAP(CMiniFlasherDlg, CDialogEx)
	ON_BN_CLICKED(IDC_BUTTON2, &CMiniFlasherDlg::OnBnClickedButton2)
	ON_BN_CLICKED(IDC_BUTTON1, &CMiniFlasherDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON3, &CMiniFlasherDlg::OnBnClickedButton3)
	ON_BN_CLICKED(IDC_BUTTON4, &CMiniFlasherDlg::OnBnClickedButton4)
END_MESSAGE_MAP()

// CMiniFlasherDlg 消息处理程序
BOOL CMiniFlasherDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);
	m_btnProg.EnableWindow(FALSE);
	m_iface.SetCurSel(theApp.GetProfileIntA("target", "tif", 1));
	m_speed.SetCurSel(theApp.GetProfileIntA("target", "speed", 4));
	m_editName.SetWindowTextA(theApp.GetProfileStringA("target", "device", "STM32F103C8"));
	m_editAddr.SetWindowTextA(theApp.GetProfileStringA("target", "addr", "0x00000000"));
	if (!JLINK_Init())
	{
		MessageBox("JLink动态库初始化失败!", "错误", MB_ICONERROR);
		EndDialog(0);
		return TRUE;
	}
	char str[64];
	DWORD ver = JLINK_GetDLLVersion();
	snprintf(str, 64, "MiniFlasher(DLL:%u.%u.%u)", ver / 10000, (ver % 10000) / 100, ver % 100);
	SetWindowText(str);
	JLINK_SetLogFile("JLink.log");
	return TRUE;
}

//修改芯片
void CMiniFlasherDlg::OnBnClickedButton2()
{
	int ret;
	JLINKARM_DEVICE_SELECT_INFO info;
	memset(&info, 0, sizeof(info));
	info.SizeOfStruct = sizeof(info);
	JLINK_Open();
	JLINK_GetHardwareVersion();
	ret = JLINK_DEVICE_SelectDialog(NULL, 0, &info);
	JLINK_Close();
	if (ret >= 0)
	{
		char addr[32];
		JLINKARM_DEVICE_INFO dev_info;
		memset(&dev_info, 0, sizeof(dev_info));
		dev_info.SizeOfStruct = sizeof(dev_info);
		JLINK_DEVICE_GetInfo(ret, &dev_info);
		m_editName.SetWindowTextA(dev_info.sName);
		snprintf(addr, sizeof(addr), "0x%08X", dev_info.FlashAddr);
		m_editAddr.SetWindowTextA(addr);
		theApp.WriteProfileStringA("target", "device", dev_info.sName);
		theApp.WriteProfileStringA("target", "addr", addr);
	}
}

//修改文件
void CMiniFlasherDlg::OnBnClickedButton1()
{
	CFileDialog fd(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_ENABLESIZING, "所有文件|*.*||");
	if (fd.DoModal() == IDOK)
	{
		CString name = fd.GetPathName();
		CString ext = name.Right(4);
		ext.MakeLower();
		m_btnProg.EnableWindow(TRUE);
		SetDlgItemText(IDC_EDIT2, name);
		if (ext == ".bin")
		{
			m_editAddr.EnableWindow(TRUE);
			return;
		}
		if (ext == ".hex")
		{
			m_editAddr.EnableWindow(FALSE);
			return;
		}
		MessageBox("无法识别的文件类型，该文件可能无法烧录!", "警告", MB_ICONWARNING);
	}
}

//擦除
void CMiniFlasherDlg::OnBnClickedButton3()
{
	DWORD ret;
	ClearMessage();
	AppendMessage("Start erase...");
	ret = JLinkSetup();
	if (ret == FALSE)
	{
		return;
	}
	AppendMessage("Erasing...");
	ret = JLINK_EraseChip();
	if (ret != 0)
	{
		AppendMessage("Erase failed: error=%d\n", ret);
	}
	else
	{
		AppendMessage("Erase OK.\n");
	}
	JLINK_Close();
}

//烧录
void CMiniFlasherDlg::OnBnClickedButton4()
{
	DWORD ret;
	ClearMessage();
	AppendMessage("Start program...");
	ret = JLinkSetup();
	if (ret == FALSE)
	{
		JLINK_Close();
		return;
	}
	AppendMessage("Programming...");
	JLINK_BeginDownload(0);
	char path[1024];
	char addr[32];
	m_editAddr.GetWindowTextA(addr, 31);
	m_editPath.GetWindowTextA(path, sizeof(path));
	ret = JLINK_DownloadFile(path, strtoul(addr, NULL, 0));
	JLINK_EndDownload();
	if (ret != 0)
	{
		AppendMessage("Programming failed: error=%d\n", ret);
	}
	else
	{
		AppendMessage("Programming OK.");
	}
	JLINK_Reset();
	JLINK_Close();
}
